package loveqq.niceexcel.core;

import lombok.Getter;
import lombok.Setter;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 合并区域(一个单元格也算)工具类
 *
 * @author: zhongjh@tsintergy.com
 * @date: 2022-05-23
 */
public class MergedRegions {
    /**
     * 单元格定位合并区域
     */
    private final Map</*行*/Integer, Map</*列*/Integer, Region>> table = new HashMap<>();

    public MergedRegions(Sheet sheet) {
        for (CellRangeAddress address : sheet.getMergedRegions()) {
            Region region = new Region(address.getFirstRow(), address.getLastRow(), address.getFirstColumn(), address.getLastColumn());
            for (int row = address.getFirstRow(); row <= address.getLastRow(); row++) {
                Map<Integer, Region> columnMap = table.computeIfAbsent(row, k -> new HashMap<>());
                for (int column = address.getFirstColumn(); column <= address.getLastColumn(); column++) {
                    columnMap.put(column, region);
                }
            }
        }
    }

    /**
     * 合并区域列数(横向), 如果该位置不存在合并区域, 返回1
     *
     * @param cell 合并区域的任意单元格
     * @return 合并区域列数
     */
    public int getWidth(Cell cell) {
        Region region = getRegion(cell);
        return 1 + (region.getLastColumn() - region.getFirstColumn());
    }

    /**
     * 合并区域行数(竖向), 如果该位置不存在合并区域, 返回1
     *
     * @param cell 合并区域的任意单元格
     * @return 合并区域行数
     */
    public int getHeight(Cell cell) {
        Region region = getRegion(cell);
        return 1 + (region.getLastRow() - region.getFirstRow());
    }

    /**
     * 获取合并区域
     *
     * @param cell 合并区域的任意单元格
     * @return 合并区域
     */
    public Region getRegion(Cell cell) {
        return Optional.ofNullable(table.get(cell.getRowIndex()))
                .map(colums -> colums.get(cell.getColumnIndex()))
                .orElseGet(() -> new Region(cell.getRowIndex(), cell.getRowIndex(), cell.getColumnIndex(), cell.getColumnIndex()));
    }

    /**
     * 获取合并区域的第一个单元格(左上角), 如果找不到合并区域, 返回入参cell自己
     *
     * @param cell 合并区域的任意单元格
     * @return 合并区域的第一个单元格
     */
    public Cell getRegionFirstCell(Cell cell) {
        return Optional.ofNullable(getRegion(cell).getFirstCell()).orElse(cell);
    }

    /**
     * 设置合并区域的第一个单元格, 方便获取合并区域的值(因为合并区域的值就是第一个单元格的值)
     *
     * @param cell 合并区域的任意单元格
     */
    public void setRegionFirstCell(Cell cell) {
        Region region = getRegion(cell);
        if (region.getFirstRow() == cell.getRowIndex() && region.getFirstColumn() == cell.getColumnIndex()) {
            region.setFirstCell(cell);
        }
    }

    /**
     * 是否合并区域的第一个单元格, 如果找不到合并区域, 返回true
     *
     * @param cell 合并区域的任意单元格
     * @return 是否合并区域的第一个单元格
     */
    public boolean isRegionFirstCell(Cell cell) {
        Region region = getRegion(cell);
        return region.getFirstRow() == cell.getRowIndex() && region.getFirstColumn() == cell.getColumnIndex();
    }


    /**
     * 合并区域
     */
    @Getter
    public static class Region {
        private final int firstRow;
        private final int lastRow;
        private final int firstColumn;
        private final int lastColumn;
        @Setter
        private Cell firstCell;

        private Region(int firstRow, int lastRow, int firstColumn, int lastColumn) {
            this.firstRow = firstRow;
            this.lastRow = lastRow;
            this.firstColumn = firstColumn;
            this.lastColumn = lastColumn;
        }
    }
}
